AWS Config Rulesのカスタムルール(Lambda連携)を触ってみた #reinvent
西澤です。先日のre:Invent 2015で発表されたAWS Config Rules。Preview申し込みも通ったので、ドキュメントで紹介されていたサンプルを試してみました。下記記事もぜひ合わせてご覧ください。
- 【速報】「AWS Config Rules」がリリースされました!!!! #reinvent
- (レポート) SEC314: AWS Configによる設定の完全な可視化と制御/NEW LAUNCH! AWS Config Rules #reinvent
- AWS Configの拡張機能「AWS Config Rules」の要素を確認してみた #reinvent
- AWS Config Rulesのマネージドルールを試してみた。 #reinvent
やってみた内容
下記ドキュメントにサンプルが紹介されていましたので、まずはこの通りやってみました。注意事項などを整理しながらご紹介したいと思います。
Getting Started with Custom Rules (Node.js)
- カスタムルール用のLambdaファンクションを作成
- AWS Configにカスタムルールを作成
カスタムルール用のLambdaファンクションを作成
サンプルコード
まずは、下記ページからzipファイルをそのままダウンロードしてきます。
- samples/InstanceTypeCheck_ConfigRuleSample.zip
- config-2014-11-12.normal.json
- InstanceTypeCheck.js
中に謎のjsonファイルが含まれています。どうやらAWS Config APIを利用する為に必要となるLibrary情報等が定義されている必須のファイルのようで、zipに含めてアップロードする必要があります。今後SDKがバージョンアップされれば不要となるのかもしれません。
InstanceTypeCheck.js
が、Lambdaから実行される実体のコードですので、こちらを覗いてみます。
var aws = require('aws-sdk'); // Include the Pre-release SDK explicitly. Once this is released into the AWS SDK, this step is not required var config = new aws.Service({ apiConfig: require('./config-2014-11-12.normal.json'), region: 'us-east-1' }); // This is where its determined whether the resource is compliant or not. // In this example, we simply decide that the resource is compliant if is an Instance and its type matches the type specified as the desired type // If the resource is not an Instance, then we deem this resource to not be applicable (if the scope of the rule is specified to only include // Instances, this rule would never have been invoked ) function evaluateCompliance(configurationItem, ruleParameters) { if(configurationItem.resourceType !== 'AWS::EC2::Instance') return 'NOT_APPLICABLE'; if(configurationItem.configuration.instanceType === ruleParameters.desiredInstanceType) return 'COMPLIANT'; else return 'NON_COMPLIANT'; } // Check whether the we're being invoked for this resource because its been deleted. If it has, then its not applicable to be evaluated function isApplicable(configurationItem) { var status = configurationItem.configurationItemStatus; return status === 'OK' || status === 'ResourceDiscovered'; } // This is the handler that's invoked by Lambda // Most of this code is boiler-plate, use as is exports.handler = function(event, context) { var invokingEvent = JSON.parse(event.invokingEvent); var ruleParameters = JSON.parse(event.ruleParameters); var compliance = 'NOT_APPLICABLE'; if (isApplicable(invokingEvent.configurationItem)) compliance = evaluateCompliance(invokingEvent.configurationItem, ruleParameters, context); // Invoke the compliance checking function. // Put together the request that reports the evaluation status // Note that we're choosing to report this evaluation against the resource that was passed in. // You can choose to report this against any other resource type, as long as it is supported by ConfigRules var putEvaluationsRequest = { Evaluations: [ { ComplianceResourceType: invokingEvent.configurationItem.resourceType, ComplianceResourceId: invokingEvent.configurationItem.resourceId, ComplianceType: compliance, OrderingTimestamp: invokingEvent.configurationItem.configurationItemCaptureTime } ], ResultToken: event.resultToken }; // Invoke the Config API to report the result of the evaluation config.putEvaluations(putEvaluationsRequest, function (err, data) { if (err) { context.fail(err); } else { context.succeed(data); } }); };
カスタムルールを開発していく上で、共通部分となるところはconfig.putEvaluations
で、各設定がcompliant(ルールに即した設定となっている)かどうかを判定した結果を返す処理になります。今回は、EC2インスタンスのインスタンスタイプがcompliantであるかどうかを判定するサンプルになります。
Lambdaファンクション作成
ドキュメントの通りにLambdaファンクションを作成します。
Lambda実行用IAMロール作成
Lambdaファンクション作成の際に、割り当てるIAMロールを作成します(事前作成も可能ですが)。通常のLambda用に最低限定義されている"Basic execution role"に加えて、config:PutEvaluations
の権限が追加で必要となる点にご注意ください。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "config:PutEvaluations" ], "Resource": "*" } ] }
Lambdaの実行テスト
ドキュメントでは、Input sample eventも用意されていました。自分で開発したときは、これを用意するのがなかなか大変だったりしたので、なんて親切なんだ!と思って実行してみたのですが。。。
真っ赤な文字だらけ。AWS Configから実行された場合だけ成功するので、InvalidResultTokenException
で良いそうです。"not authorized to perform: config:PutEvaluations."が出たら、権限不足とのことなので、これを信じて先に進みましょう。
LambdaファンクションへのAWS Configからの実行権限付与
Lambdaファンクションにリソースベースで権限を付ける必要があるとのこと。AWS Management Consoleでは見当たらなかったので、Lambdaファンクションに権限を付けて制御できることは、ここで初めて知りました。AWS ConfigがこのLambdaファンクションを実行できるように設定しておきます。
$ aws lambda add-permission \ --function-name InstanceTypeCheck \ --statement-id "AddConfigPermission" \ --action lambda:InvokeFunction \ --principal config.amazonaws.com { "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-1:<AWS ACCOUNT ID>:function:InstanceTypeCheck\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"config.amazonaws.com\"},\"Sid\":\"AddConfigPermission\"}],\"Id\":\"default\"}" } $ aws lambda get-policy \ --function-name InstanceTypeCheck { "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-1:<AWS ACCOUNT ID>:function:InstanceTypeCheck\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"config.amazonaws.com\"},\"Sid\":\"AddConfigPermission\"}],\"Id\":\"default\"}" }
AWS Configにカスタムルールを作成
こちらもドキュメントの通りにやってみましょう。
ここで、Lambdaに登録したスクリプト内にある外部パラメータを指定して、判定を行っています。
- Key=desiredInstanceType
- Value=t2.micro
AWS Configの作成はとてもシンプルですね。
テスト
いよいよテストです。試しに、t2.microとt2.smallをそれぞれ1台ずつ起動してみました。
1台が"Compliant"、もう1台が"Noncopliant"で画面表示されました!
まとめ
今回はサンプルを利用してAWS Config Rulesのカスタムルールを試してみました。CloudTrailとごちゃ混ぜになってしまっていたのですが、AWS Configの武器は過去の状態を追跡できること、ということを再認識しました。あとLambdaももっとトレーニングを積まないといけないですね。
今後もAWS Configの特徴を生かしたカスタムルールを考えて行きたいと思います。AWS Config Rulesの正式リリースが待たれます。